#include "XPLMPlugin.h"
#include "XPLMUtilities.h"
#include "XPLMProcessing.h"
#include "XPLMMenus.h"
#include "XPLMGraphics.h"
#include "XPLMPlanes.h"
#include "XPLMDataAccess.h"
#include "XPLMNavigation.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include <cerrno>

#include <string>
#include <cstring>
#include <iostream>

#define LINUX_OS
//#define WIN_OS


/*#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
*/

#ifdef LINUX_OS
 #include <netdb.h>
#endif

#ifdef WIN_OS
 #include <Winsock2.h>
#endif


#if IBM
#include <windows.h>
#endif


#define XFSE_VERSION "2.0 Beta"



int MenuItem1;

/// Widgets
XPWidgetID XFSEWidget = NULL, XFSEWindow1 = NULL, XFSEWindow2 = NULL, XFSEWindow3 = NULL;
XPWidgetID LoginUserCaption, LoginUserEdit, LoginPassCaption, LoginButton, LoginPassEdit, ServerResponseCaption, AssignmentListCaption;
XPWidgetID ErrorCaption[3], FromCaption[255], ToCaption[255], CargoCaption[255], ACRegCaption, LeaseCaption, CurrentTimeCaption;
XPWidgetID StartFlyButton, CancelFlyButton, XFSEScrollbar, UpdateButton;

void * userstr;
void * passstr;

/// Utility functions and callbacks

/// This is used to get around a sprintf float bug with codewarrior on the mac
#if IBM || LIN
inline	float	HACKFLOAT(float val)
{
	return val;
}
#else
inline long long HACKFLOAT(float val)
{
	double	d = val;
	long long temp;
	temp = *((long long *) &d);
	return temp;
}
#endif

void XFSEMenuHandler(void *, void *);
void CreateXFSEWidget(int x1, int y1, int w, int h);
long GetCBIndex(long Type);


std::string XFSEpost(std::string request) {
	const char * r;
	r = request.c_str();
	static const char *BODY = r;
	static const char *HEADERS = "POST http://atilla.hinttech.com/fseconomy/fsagentFSX HTTP/1.0\r\n"
	"Host: atilla.hinttech.com\r\n"
	"Accept: */*\r\n"
	"Connection: keep-alive\r\n"
	"Content-Type: application/x-www-form-urlencoded\r\n"
	"Content-Length: ";

	   struct addrinfo req, *res;
	   memset(&req, 0, sizeof(req));
	   req.ai_family = AF_UNSPEC;
	   req.ai_socktype = SOCK_STREAM;

	   if (getaddrinfo("atilla.hinttech.com", "http", &req, &res) < 0)
	   {
	      perror("getaddrinfo");
	      return "Error: FSE server is offline.";
	   }

	   int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	   if (s < 0)
	   {
	      perror("Error: socket error");
	      return "Error: socket error";
	   }
	   if (connect(s, res->ai_addr, res->ai_addrlen) < 0)
	   {
	      perror("connect");
	      close(s);
	      return "Error: connect error";
	   }

	   char *buffer = (char*)malloc(strlen(BODY) + strlen(HEADERS) + 256);
	   sprintf(buffer, "%s%d\r\n\r\n%s\r\n\r\n", HEADERS, strlen(BODY), BODY);
	   if (send(s, buffer, strlen(buffer), 0) < 0)
	   {
	      perror("send");
	   }
	   else
	   {
	      char recvbuffer[2048] = { 0 };
	      int recvcount = 0;
	      std::string str;
	      recvcount = recv(s, recvbuffer, sizeof(recvbuffer), 0);
	      while (recvcount > 0)
	      {
	    	 str.append(recvbuffer);
	         recvcount = recv(s, recvbuffer, sizeof(recvbuffer), 0);
	      }

	      std::cout << str.substr(str.find("<"),str.length()) << std::endl;

	      return str.substr(str.find("<"),str.length());


	   }
	   free(buffer);
	   close(s);
	   return 0;

}

int XFSEHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						long					inParam1,
						long					inParam2);


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	XPLMMenuID	id;
	int			item;

	strcpy(outName, "X-Economy");
	strcpy(outSig, "xpsdk.experimental.XFSE");
	strcpy(outDesc, "X-Economy - plugin for FSEconomy (www.fseconomy.com)");

	// Create our menu
	item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "X-Economy", NULL, 1);
	id = XPLMCreateMenu("X-Economy", XPLMFindPluginsMenu(), item, XFSEMenuHandler, NULL);
	XPLMAppendMenuItem(id, "Open X-Economy", (void *)"X-Economy", 1);

	// Flag to tell us if the widget is being displayed.
	MenuItem1 = 0;


	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	if (MenuItem1 == 1)
	{
		XPDestroyWidget(XFSEWidget, 1);
		MenuItem1 = 0;
	}
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, long inMsg, void * inParam)
{
}


// This will create our widget from menu selection.
// MenuItem1 flag stops it from being created more than once.
void XFSEMenuHandler(void * mRef, void * iRef)
{
	// If menu selected create our widget dialog
	if (!strcmp((char *) iRef, "X-Economy"))
	{
		if (MenuItem1 == 0)
		{
			CreateXFSEWidget(221, 640, 480, 490);
			MenuItem1 = 1;
		}
		else
			if(!XPIsWidgetVisible(XFSEWidget))
				XPShowWidget(XFSEWidget);
	}
}


// This will create our widget dialog.
// I have made all child widgets relative to the input paramter.
// This makes it easy to position the dialog
void CreateXFSEWidget(int x, int y, int w, int h)
{
	int x2 = x + w;
	int y2 = y - h;
	char Buffer[255];
	char _userINI[255];
	char _passINI[255];

	strcpy(Buffer, "X-Economy");

	// Create the Main Widget window
	XFSEWidget = XPCreateWidget(x, y, x2, y2, 1, Buffer, 1,	NULL, xpWidgetClass_MainWindow);

	///Add Close Box decorations to the Main Widget
	XPSetWidgetProperty(XFSEWidget, xpProperty_MainWindowHasCloseBoxes, 1);


	///Create the Sub Widget1 window
	XFSEWindow1 = XPCreateWidget(x+10, y-30, x2-10, y2+200,
					     1,
					     "",
					     0,
					     XFSEWidget,
					     xpWidgetClass_SubWindow);



	/// Set the style to sub window
	XPSetWidgetProperty(XFSEWindow1, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	///Create the Sub Widget2 window
	XFSEWindow2 = XPCreateWidget(x+10, y-100, x2-10, y2+10,
					     1,
					     "",
					     0,
					     XFSEWidget,
					     xpWidgetClass_SubWindow);

	///Set the style to sub window
	XPSetWidgetProperty(XFSEWindow2, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	XFSEWindow3 = XPCreateWidget(x+15, y-130, x2-35, y2+150,
					     1,
					     "",
					     0,
					     XFSEWidget,
					     xpWidgetClass_SubWindow);

	/// Set the style to sub window
	XPSetWidgetProperty(XFSEWindow2, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	// Login user caption
	LoginUserCaption = XPCreateWidget(x+20, y-40, x+50, y-60,1, "Username:", 0, XFSEWidget,xpWidgetClass_Caption);

	// Login user field
	LoginUserEdit = XPCreateWidget(x+80, y-40, x+160, y-60,1, _userINI, 0, XFSEWidget,xpWidgetClass_TextField);
	XPSetWidgetProperty(LoginUserEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(LoginUserEdit, xpProperty_Enabled, 1);

	//Login pass caption
	LoginPassCaption = XPCreateWidget(x+20, y-60, x+50, y-80,1, "Password:", 0, XFSEWidget,xpWidgetClass_Caption);

	// Login user field
	LoginPassEdit = XPCreateWidget(x+80, y-60, x+160, y-80,1, _passINI, 0, XFSEWidget,xpWidgetClass_TextField);
	XPSetWidgetProperty(LoginPassEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(LoginPassEdit, xpProperty_Enabled, 1);
	XPSetWidgetProperty(LoginPassEdit, xpProperty_PasswordMode, 1);

	// Login button
	LoginButton = XPCreateWidget(x+180, y-40, x+260, y-60,1, "Log in", 0, XFSEWidget,xpWidgetClass_Button);
	XPSetWidgetProperty(LoginButton, xpProperty_ButtonType, xpPushButton);

	// Server response text
	ServerResponseCaption = XPCreateWidget(x+180, y-60, x+260, y-80,1, "You're not logged in", 0, XFSEWidget,xpWidgetClass_Caption);

	// Assignments text
	AssignmentListCaption = XPCreateWidget(x+20, y-105, x+50, y-125,1, "Assignment info:", 0, XFSEWidget,xpWidgetClass_Caption);

	// Error text
	ErrorCaption[0] = XPCreateWidget(x+20, y-410, x+50, y-430,1, "", 0, XFSEWidget,xpWidgetClass_Caption);

	// Error2 text
	ErrorCaption[1] = XPCreateWidget(x+20, y-420, x+50, y-440,1, "", 0, XFSEWidget,xpWidgetClass_Caption);

	// Error3 text
	ErrorCaption[2] = XPCreateWidget(x+20, y-430, x+50, y-450,1, "", 0, XFSEWidget,xpWidgetClass_Caption);

	// From
	//FromCaption[0] = XPCreateWidget(x+20, y-120, x+50, y-140,1, "", 0, XFSEWidget,xpWidgetClass_Caption);

	// To
	//ToCaption[0] = XPCreateWidget(x+140, y-120, x+170, y-140,1, "", 0, XFSEWidget,xpWidgetClass_Caption);

	// Cargo
	//CargoCaption[0] = XPCreateWidget(x+210, y-120, x+240, y-140,1, "", 0, XFSEWidget,xpWidgetClass_Caption);

/*		# Comment
		#self.CommentCaption=[]
		#self.CommentCaption.append(XPCreateWidget(x+20, y-140, x+50, y-160,1, "Comment: -", 0, self.XFSEWidget,xpWidgetClass_Caption))*/

	// AC reg
	ACRegCaption = XPCreateWidget(x+20, y-340, x+50, y-360,1, "Aircraft registration: -", 0, XFSEWidget,xpWidgetClass_Caption);

	// Lease expires
	LeaseCaption = XPCreateWidget(x+20, y-360, x+50, y-380,1, "Lease time: -", 0, XFSEWidget,xpWidgetClass_Caption);

	// Current flight time
	CurrentTimeCaption = XPCreateWidget(x+20, y-330, x+50, y-450,1, "Current flight time: -", 0, XFSEWidget,xpWidgetClass_Caption);


	// Start fly button
	StartFlyButton = XPCreateWidget(x+360, y-40, x+450, y-60,
						 1, "Start flying", 0, XFSEWidget,
						 xpWidgetClass_Button);

	XPSetWidgetProperty(StartFlyButton, xpProperty_ButtonType, xpPushButton);
	XPSetWidgetProperty(StartFlyButton, xpProperty_Enabled, 0);


	//cancel fly button
	CancelFlyButton = XPCreateWidget(x+360, y-60, x+450, y-80,
						  1, "Cancel flight", 0, XFSEWidget,
						  xpWidgetClass_Button);

	XPSetWidgetProperty(CancelFlyButton, xpProperty_ButtonType, xpPushButton);
	XPSetWidgetProperty(CancelFlyButton, xpProperty_Enabled, 0);


	XFSEScrollbar = XPCreateWidget(x+445, y-130, x2-10, y2+150, 1, "", 0,	XFSEWidget, xpWidgetClass_ScrollBar);
	XPSetWidgetProperty(XFSEScrollbar,xpProperty_ScrollBarMin, 0);

	UpdateButton = XPCreateWidget(x+370, y-410, x+450, y-430,1, "Update client", 0, XFSEWidget,xpWidgetClass_Button);
	XPSetWidgetProperty(UpdateButton, xpProperty_ButtonType, xpPushButton);
	XPSetWidgetProperty(UpdateButton, xpProperty_Enabled, 0);
	// print "window ready"

	// Register our widget handler
	XPAddWidgetCallback(XFSEWidget, XFSEHandler);
}



// This is the handler for our widget
// It can be used to process button presses etc.
// In this example we are only interested when the close box is pressed
int	XFSEHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						long					inParam1,
						long					inParam2)
{
	void *Param;
	Param = 0;
	/// char Buffer[255];

	if (inMessage == xpMessage_CloseButtonPushed)
	{
		if (MenuItem1 == 1)
		{
			XPHideWidget(XFSEWidget);
		}
		return 1;
	}

	if (inMessage == xpMsg_PushButtonPressed)
	{


		if (inParam1 == (long)LoginButton) {

			// print "login"
			char Buffer[255];

			XPGetWidgetDescriptor(LoginUserEdit,Buffer,sizeof(Buffer)-1);
			std::string userstr = Buffer;
			XPGetWidgetDescriptor(LoginPassEdit,Buffer,sizeof(Buffer)-1);
			std::string passstr = Buffer;


			XFSEpost("user="+userstr+"&pass="+passstr+"&action=accountCheck");


			/*
			 * logincheck = XFSEpost("user="+userstr+"&pass="+passstr+"&action=accountCheck");
			*/


			/*#print "logincheck"


			if (logincheck.getElementsByTagName('response')[0].firstChild.nodeName=="ok"):
				XPSetWidgetDescriptor(self.ServerResponseCaption, "Logged in!")
				XPSetWidgetProperty(self.LoginButton, xpProperty_Enabled, 0)
				XPSetWidgetProperty(self.StartFlyButton, xpProperty_Enabled, 1)
				#print "login successful"

			else:
				#print "login was not successful"

				if(logincheck.getElementsByTagName('response')[0].firstChild.nodeName=="notok"):
					XPSetWidgetDescriptor(self.ServerResponseCaption, "New version available, see below...")
					XPSetWidgetDescriptor(self.ErrorCaption[0], "!!! New version is available: v"+str(logincheck.getElementsByTagName('notok')[0].firstChild.data))
					XPSetWidgetProperty(self.UpdateButton, xpProperty_Enabled, 1)
					#print "new version avail"

				else:
					XPSetWidgetDescriptor(self.ServerResponseCaption, "Invalid account!")
					#print "invalid account"

			logincheck.unlink()*/
			return 1;
		}

		/* ----------------------------------------------------------------------------------------------------- */

		/*

		if (inParam1 == (long)ClearEntryButton)
		{
		    XPLMClearFMSEntry(XPLMGetDisplayedFMSEntry());
			return 1;
		}

		if (inParam1 == (long)GetEntryIndexButton)
		{
		    long Index = XPLMGetDisplayedFMSEntry();
			sprintf(Buffer, "%d", Index);
			XPSetWidgetDescriptor(EntryIndexEdit, Buffer);
			return 1;
		}

		if (inParam1 == (long)SetEntryIndexButton)
		{
			XPGetWidgetDescriptor(EntryIndexEdit, Buffer, sizeof(Buffer));
		    long Index = atoi(Buffer);
			XPLMSetDisplayedFMSEntry(Index);
			return 1;
		}

		if (inParam1 == (long)GetDestinationEntryButton)
		{
		    long Index = XPLMGetDestinationFMSEntry();
			sprintf(Buffer, "%d", Index);
			XPSetWidgetDescriptor(DestinationEntryIndexEdit, Buffer);
			return 1;
		}

		if (inParam1 == (long)SetDestinationEntryButton)
		{
			XPGetWidgetDescriptor(DestinationEntryIndexEdit, Buffer, sizeof(Buffer));
		    long Index = atoi(Buffer);
			XPLMSetDestinationFMSEntry(Index);
			return 1;
		}

		if (inParam1 == (long)GetNumberOfEntriesButton)
		{
		    long Count = XPLMCountFMSEntries();
			sprintf(Buffer, "%d", Count);
			XPSetWidgetDescriptor(GetNumberOfEntriesText, Buffer);
			return 1;
		}

		if (inParam1 == (long)GetFMSEntryButton)
		{
			long Index = XPLMGetDisplayedFMSEntry();
		    XPLMNavType outType;
			char outID[80];
			XPLMNavRef outRef;
			long outAltitude;
			float outLat;
			float outLon;

			XPLMGetFMSEntryInfo(Index, &outType, outID, &outRef, &outAltitude, &outLat, &outLon);
			sprintf(Buffer, "%d", Index);
			XPSetWidgetDescriptor(IndexEdit, Buffer);
			sprintf(Buffer, "%d", Index+1);
			XPSetWidgetDescriptor(SegmentCaption2, Buffer);
			if (outType == xplm_Nav_LatLon)
				XPSetWidgetDescriptor(AirportIDEdit, "----");
			else
				XPSetWidgetDescriptor(AirportIDEdit, outID);
			sprintf(Buffer, "%d", outAltitude);
			XPSetWidgetDescriptor(AltitudeEdit, Buffer);
			XPSetWidgetDescriptor(NavTypeEdit, NavTypeLookup[GetCBIndex(outType)].Description);
			sprintf(Buffer, "%d", NavTypeLookup[GetCBIndex(outType)].EnumValue);
			XPSetWidgetDescriptor(NavTypeText, Buffer);
			sprintf(Buffer, "%+05.2f", HACKFLOAT(outLat));
			XPSetWidgetDescriptor(LatEdit, Buffer);
			sprintf(Buffer, "%+05.2f", HACKFLOAT(outLon));
			XPSetWidgetDescriptor(LonEdit, Buffer);

			return 1;
		}

		if (inParam1 == (long)SetFMSEntryButton)
		{
			XPGetWidgetDescriptor(IndexEdit, Buffer, sizeof(Buffer));
			long Index = atoi(Buffer);
			sprintf(Buffer, "%d", Index+1);
			XPSetWidgetDescriptor(SegmentCaption2, Buffer);
			XPGetWidgetDescriptor(AltitudeEdit, Buffer, sizeof(Buffer));
			long Altitude = atoi(Buffer);
			XPGetWidgetDescriptor(NavTypeText, Buffer, sizeof(Buffer));
			int NavType = atoi(Buffer);
			XPGetWidgetDescriptor(AirportIDEdit, Buffer, sizeof(Buffer));
			XPLMSetFMSEntryInfo(Index, XPLMFindNavAid(NULL, Buffer, NULL, NULL, NULL, NavType), Altitude);

			return 1;
		}

		if (inParam1 == (long)SetLatLonButton)
		{
			XPGetWidgetDescriptor(IndexEdit, Buffer, sizeof(Buffer));
			long Index = atoi(Buffer);
			sprintf(Buffer, "%d", Index+1);
			XPSetWidgetDescriptor(SegmentCaption2, Buffer);
			XPGetWidgetDescriptor(AltitudeEdit, Buffer, sizeof(Buffer));
			long Altitude = atoi(Buffer);
			XPGetWidgetDescriptor(LatEdit, Buffer, sizeof(Buffer));
			float Lat = atof(Buffer);
			XPGetWidgetDescriptor(LonEdit, Buffer, sizeof(Buffer));
			float Lon = atof(Buffer);
			XPLMSetFMSEntryLatLon(Index, Lat, Lon, Altitude);

			return 1;
		}

		// Up Arrow is used to modify the NavTypeLookup Array Index
		if (inParam1 == (long)UpArrow)
		{
			NavTypeLinePosition--;
			if (NavTypeLinePosition < 0)
				NavTypeLinePosition = MAX_NAV_TYPES-1;
			XPSetWidgetDescriptor(NavTypeEdit, NavTypeLookup[NavTypeLinePosition].Description);
			sprintf(Buffer, "%d", NavTypeLookup[NavTypeLinePosition].EnumValue);
			XPSetWidgetDescriptor(NavTypeText, Buffer);

			return 1;
		}

		// Down Arrow is used to modify the NavTypeLookup Array Index
		if (inParam1 == (long)DownArrow)
		{
			NavTypeLinePosition++;
			if (NavTypeLinePosition > MAX_NAV_TYPES-1)
				NavTypeLinePosition = 0;
			XPSetWidgetDescriptor(NavTypeEdit, NavTypeLookup[NavTypeLinePosition].Description);
			sprintf(Buffer, "%d", NavTypeLookup[NavTypeLinePosition].EnumValue);
			XPSetWidgetDescriptor(NavTypeText, Buffer);

			return 1;
		}*/


	}

	return 0;
}





